package com.wt.admin.service.file.impl;

import cn.hutool.core.util.StrUtil;
import com.aizuda.easy.security.code.BasicCode;
import com.aizuda.easy.security.domain.Rep;
import com.aizuda.easy.security.exp.impl.BasicException;
import com.aizuda.easy.security.server.EasySecurityServer;
import com.aizuda.easy.security.util.LocalUtil;
import com.wt.admin.config.prop.IndexProp;
import com.wt.admin.controller.FileController;
import com.wt.admin.domain.vo.sys.UserVO;
import com.wt.admin.service.file.FileService;
import com.wt.admin.util.AssertUtil;
import lombok.SneakyThrows;
import org.apache.commons.io.FileUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Service
public class FileServiceImpl implements FileService {

    @Resource
    private IndexProp indexProp;
    @Resource
    private UploadFileStrategy uploadFileStrategy;
    private String tempDir;

    @Override
    public void init(){
        tempDir = indexProp.getFiles().getSavePath() + "temp/";
    }

    @Override
    public String uploadLocal(MultipartFile file, String path, HttpServletRequest httpServletRequest) throws IOException {
        String name = file.getOriginalFilename();
        String string = UUID.randomUUID().toString().replace("-", "");
        name = string + (name.contains(".") ? name.substring(name.indexOf(".")) : "");
        File fil = new File(indexProp.getFiles().getSavePath() + path + "/" + name);
        InputStream inputStream = file.getInputStream();
        FileUtils.copyInputStreamToFile(inputStream, fil);
        inputStream.close();
        return indexProp.getFiles().getSource().replace("*", "") + path + "/" + name;
    }

    @Override
    public String uploadStrategy(MultipartFile file, String path, HttpServletRequest httpServletRequest) throws IOException, BasicException {
        AssertUtil.objIsNull(file, BasicCode.BASIC_CODE_99999);
        String s = uploadLocal(file, path, httpServletRequest);
        Map<String, String[]> parameterMap = httpServletRequest.getParameterMap();
        UserVO userVO = LocalUtil.getUser();
        uploadFileStrategy.exec(s, file, parameterMap, userVO);
        return s;
    }


    @SneakyThrows
    @Override
    public List<String> uploadLocalBatch(MultipartFile[] file, String path, HttpServletRequest httpServletRequest) {
        AssertUtil.List.isEmpty(file, BasicCode.BASIC_CODE_99999);
        List<String> list = new ArrayList<>(file.length);
        for (MultipartFile multipartFile : file) {
            list.add(uploadLocal(multipartFile, path, httpServletRequest));
        }
        return list;
    }

    @SneakyThrows
    @Override
    public List<String> uploadStrategyBatch(MultipartFile[] file, String path, HttpServletRequest httpServletRequest) {
        AssertUtil.List.isEmpty(file, BasicCode.BASIC_CODE_99999);
        Map<String,MultipartFile> map = new HashMap<>(file.length);
        for (MultipartFile multipartFile : file) {
            map.put(uploadLocal(multipartFile, path, httpServletRequest), multipartFile);
        }
        Map<String, String[]> parameterMap = httpServletRequest.getParameterMap();
        uploadFileStrategy.batchExec(map, parameterMap, LocalUtil.getUser());
        return map.keySet().stream().toList();
    }

    @SneakyThrows
    @Override
    public void saveChunk(MultipartFile file, String fileHash, String fileName, int chunkIndex, int totalChunks) {
        Path directory = Paths.get(tempDir, fileHash);
        Files.createDirectories(directory);
        Path chunkPath = directory.resolve(fileName + ".part" + chunkIndex);
        file.transferTo(chunkPath.toFile());
    }

    @SneakyThrows
    @Override
    public List<Integer> getExistingChunks(String fileHash) {
        // 构建临时存储分片的目录路径
        Path directory = Paths.get(tempDir, fileHash);
        File dir = directory.toFile();
        // 如果目录不存在或不是文件夹，返回空列表
        if (!dir.exists() || !dir.isDirectory()) {
            return new ArrayList<>();
        }
        // 获取目录下所有分片文件
        File[] files = dir.listFiles();
        if (files == null) {
            return new ArrayList<>();
        }
        // 返回已存在的分片索引列表
        return IntStream.range(0, files.length).boxed().collect(Collectors.toList());
    }

    @SneakyThrows
    @Override
    public String mergeChunks(FileController.MergeRequest request) {
        Path tempDirPath = Paths.get(tempDir, request.getFileHash());
        Path finalDirPath = Paths.get(indexProp.getFiles().getSavePath() + request.getPath());

        Files.createDirectories(finalDirPath);
        Path finalFilePath = finalDirPath.resolve(request.getFileName());

        try (RandomAccessFile destFile = new RandomAccessFile(finalFilePath.toFile(), "rw")) {
            for (int i = 0; i < request.getTotalChunks(); i++) {
                Path chunkPath = tempDirPath.resolve(request.getFileName() + ".part" + i);
                File chunkFile = chunkPath.toFile();

                if (!chunkFile.exists()) {
                    throw new FileNotFoundException("缺少块文件: " + chunkPath);
                }
                try (FileInputStream fis = new FileInputStream(chunkFile); BufferedInputStream bis = new BufferedInputStream(fis)) {
                    byte[] buffer = new byte[8192];
                    int bytesRead;
                    while ((bytesRead = bis.read(buffer)) != -1) {
                        destFile.write(buffer, 0, bytesRead);
                    }
                }
                // 删除已合并的块
                Files.delete(chunkPath);
            }
        }
        // 删除临时目录
        if (tempDirPath.toFile().exists()) {
            Files.delete(tempDirPath);
        }
        return indexProp.getFiles().getSource().replace("*", "") + request.getPath() + "/" + request.getFileName();
    }

}
